{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Build a Docker image for an MCP server \n",
    "This tutorial builds a Docker image for an MCP server using Podman, specifically tailored for deploying on Anyscale with Ray Serve. It complements the official Anthropic tutorial for [Building the MCP weather server](https://modelcontextprotocol.io/quickstart/server), which doesn't include Docker image-building instructions.\n",
    "\n",
    "Docker simplifies the process of building and distributing MCP servers by packaging them into standardized, portable containers. This eliminates issues related to dependencies and environment configuration. It also enables streamlined cloud development—enhancing testing, security, and cross-platform deployment for agent-focused tools.\n",
    "\n",
    "Unfortunately, you can't use the [Anyscale Docker image build farm](https://docs.anyscale.com/configuration/dependency-management/dependency-container-images/) to build this image, as it doesn't support the Docker `COPY` command from local storage.\n",
    "\n",
    "Therefore, this tutorial shows you how to build the MCP Docker image directly from the Anyscale workspace. Alternatively, you can also [build it from your local machine](https://docs.anyscale.com/container-image/build-image-tutorial). \n",
    "\n",
    "See https://hub.docker.com/catalogs/mcp for the Docker images collection for MCP servers. "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Prerequisites and folder layout\n",
    "Install the Podman: \n",
    "```bash\n",
    "sudo apt-get update && sudo apt-get install -y podman\n",
    "```\n",
    "\n",
    "Ensure you have Podman successfully installed:\n",
    "```bash\n",
    "podman --version\n",
    "```\n",
    "\n",
    "See the `build-mcp-docker-image` folder that contains the following files:\n",
    "\n",
    "```text\n",
    "build-mcp-docker-image/\n",
    "├── Dockerfile     \n",
    "├── requirements.txt\n",
    "└── weather.py      \n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 1. Dockerfile for a weather MCP server\n",
    "\n",
    "This Dockerfile creates a lightweight image based on `python3.10` for running a weather MCP server. It installs system dependencies and the [`uv`](https://github.com/astral-sh/uv) CLI tool for efficient package and application management. \n",
    "\n",
    "The Dockerfile sets the working directory to `/app`, installs Python packages from `requirements.txt` using uv, copies the full project into the container, and finally runs the `weather.py` server script using `uv`.\n",
    "\n",
    "\n",
    "```python\n",
    "# Use Python 3.10 base image.\n",
    "FROM python:3.10-slim\n",
    "\n",
    "# Install system dependencies.\n",
    "RUN apt-get update && \\\n",
    "    apt-get install -y curl ca-certificates && \\\n",
    "    rm -rf /var/lib/apt/lists/*\n",
    "\n",
    "# Install the 'uv' CLI.\n",
    "RUN curl -LsSf https://astral.sh/uv/install.sh | sh\n",
    "\n",
    "# Make sure 'uv' is on PATH.\n",
    "ENV PATH=\"/root/.local/bin:${PATH}\"\n",
    "\n",
    "# Set the working directory.\n",
    "WORKDIR /app\n",
    "\n",
    "# Copy and install only requirements first (caching).\n",
    "COPY requirements.txt .\n",
    "RUN uv pip install --system -r requirements.txt\n",
    "\n",
    "# Now copy everything from the current directory into /app.\n",
    "COPY . .\n",
    "\n",
    "# Run the server.\n",
    "CMD [\"uv\", \"run\", \"weather.py\"]\n",
    "```\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 2.  Build a Docker image with Podman\n",
    "\n",
    "Navigate to the project directory:\n",
    "\n",
    "```bash\n",
    "cd build-mcp-docker-image\n",
    "```\n",
    "\n",
    "Run the following Podman command to build the Docker image, ensuring you use the --events-backend=file flag to prevent build errors on Anyscale:\n",
    "```bash\n",
    "podman build \\\n",
    "  --events-backend=file \\\n",
    "  --cgroup-manager=cgroupfs \\\n",
    "  -t weather-mcp:latest .\n",
    "```\n",
    "\n",
    "**Note**: \n",
    "\n",
    "Omitting the `--events-backend=file` flag may result in the following error:\n",
    "```text\n",
    "ERRO[0000] unable to write build event: \"write unixgram @11c5a->/run/systemd/journal/socket: sendmsg: no such file or directory\"\n",
    "```\n",
    "\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 3. Push the Docker image to registry\n",
    "\n",
    "Push the built image to your own container registry. You should replace `your-dockerhub-username/weather-mcp` with your actual image name:\n",
    "\n",
    "```bash\n",
    "podman tag weather-mcp:latest your-dockerhub-username/weather-mcp:latest\n",
    "\n",
    "podman push \\\n",
    "  --events-backend=file \\\n",
    "  your-dockerhub-username/weather-mcp:latest ## make sure replace with your own dockerhub username or repo\n",
    "```\n",
    "\n",
    "Make sure you're logged into your Docker Hub account or container registry before pushing:\n",
    "```bash\n",
    "podman login docker.io\n",
    "```\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Next steps\n",
    "You have successfully built and pushed a Docker image for your MCP server, which is ready to deploy.\n",
    "\n",
    "Once you push the image, you can deploy the MCP server on Anyscale using Ray Serve. \n",
    "\n",
    "Follow the next two tutorials for single and multiple MCP server deployments using Ray Serve."
   ]
  }
 ],
 "metadata": {
  "language_info": {
   "name": "python"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
